/*****************************************************
** Author:
** Date: 2019-08-03
*
*****************************************************/

#ifndef __PCA9685_H_
#define __PCA9685_H_

#ifdef __cplusplus
extern "C"{
#endif

#include <stdbool.h>

enum
{
    PCA9685_REG_MODE1 = 0x00,
    PCA9685_REG_MODE2 = 0x01,
    PCA9685_REG_SUBADR1 = 0x02,
    PCA9685_REG_SUBADR2 = 0x03,
    PCA9685_REG_SUBADR3 = 0x04,
    PCA9685_REG_ALLCALLADR = 0x05,
    PCA9685_REG_LED0_ON_L = 0x06,
    PCA9685_REG_LED0_ON_H = 0x07,
    PCA9685_REG_LED0_OFF_L = 0x08,
    PCA9685_REG_LED0_OFF_H = 0x09,
    PCA9685_REG_ALL_LED_ON_L = 0xfa,
    PCA9685_REG_ALL_LED_ON_H = 0xfb,
    PCA9685_REG_ALL_LED_OFF_L = 0xfc,
    PCA9685_REG_ALL_LED_OFF_H = 0xfd,
    PCA9685_REG_PRE_SCALE = 0xfe,
    PCA9685_REG_TESTMODE = 0xff,
};

#define PCA9685_MODE1_RESTART_BIT   (1<<7)
#define PCA9685_MODE1_EXTCLK_BIT    (1<<6)
#define PCA9685_MODE1_AI_BIT        (1<<5)
#define PCA9685_MODE1_SLEEP_BIT     (1<<4)
#define PCA9685_MODE1_SUB1_BIT      (1<<3)
#define PCA9685_MODE1_SUB2_BIT      (1<<2)
#define PCA9685_MODE1_SUB3_BIT      (1<<1)
#define PCA9685_MODE1_ALLCALL_BIT   (1<<0)

#define PCA9685_LED_FULL_BIT        (1<<4)

enum {
	DC_MOTOR_RUNSTATE_IDLE,
	DC_MOTOR_RUNSTATE_FORWARD,
	DC_MOTOR_RUNSTATE_BACKWARD,
};


typedef void * Pca9685ObjHdl;
typedef void * ServoObjHdl;
typedef void * DcMotorObjHdl;

typedef struct {
	void (*selChipCb)(int level);
	int  (*i2cReadCb)(unsigned char *pbuf, int len);
	int  (*i2cWriteCb)(unsigned char *pbuf, int len);
	void (*delayUsCb)(unsigned int us);
	void (*delayMsCb)(unsigned int ms);
} Pca9685CbStru;

typedef struct {
    unsigned short deadZone;
    unsigned short minPwm;
    unsigned short maxPwm;
    unsigned short pwm;
    unsigned short step;
    // unsigned int delayMs;
} Pca9685ParamStru;


void Pca9685RegisterMalloc(void *(*malloc)(unsigned int size), void (*free)(void *ptr));
Pca9685ObjHdl Pca9685Init(Pca9685CbStru *cfg, int freq);
void Pca9685Deinit(Pca9685ObjHdl hdl);
void Pca9685SetPwm(Pca9685ObjHdl hdl, unsigned short channel, unsigned short on, unsigned short off);
void Pca9685SetPwmFull(Pca9685ObjHdl hdl, unsigned short channel, bool full);

ServoObjHdl ServoInit(Pca9685ObjHdl pca9685, Pca9685ParamStru *param, unsigned short channel);
void ServoDeinit(ServoObjHdl hdl);
/*
 *	pwm: (0,4096-deadZone]
 */
void ServoSetPulse(ServoObjHdl hdl, unsigned short pwm);
void ServoIncreasePwm(ServoObjHdl hdl);
void ServoDecreasePwm(ServoObjHdl hdl);
void ServoSetAngle(ServoObjHdl hdl, unsigned short angle);

DcMotorObjHdl DcMotorInit(Pca9685ObjHdl *pca9685, Pca9685ParamStru *param,
	unsigned short chanForward, unsigned short chanBackward);
void DcMotorDeinit(DcMotorObjHdl hdl);
void DcMotorRunPwm(DcMotorObjHdl hdl, int direction, unsigned short pwm);
void DcMotorFullSpeed(DcMotorObjHdl hdl, int direction);


#ifdef __cplusplus
}
#endif

#endif /* __PCA9685_H_ */

